連假終於來啦~~~今天筆者久違的回了一趟公館,吃到好多學生時代的回憶感覺非常懷念d(`・∀・)b
今天來稍微寫個小品系列,就是pluginlib,這個package是用來動態載入plugin的工具,不過這些plugin需要在package.xml中列出來才有效。plugin感覺起來是用來做多型的處理,原本package內定義的class,經過他人接手後需要新增別的實作的class,就可以用plugin來插入一個新的class,因此不會影響到原本的package功能這樣。
以官網的圖片為例,原本的polygon_interface這個package內只是一個虛擬的class,沒有任何實作,但因為加入兩個plugin: rectangle_plugin和triangle_plugin,讓polygon_interface有了實作的class可供使用這樣。
以上述的polygon為例,先建立一個虛擬的class:
in polygon_base.h:
#ifndef PLUGINLIB_TUTORIALS__POLYGON_BASE_H_
#define PLUGINLIB_TUTORIALS__POLYGON_BASE_H_
namespace polygon_base
{
class RegularPolygon
{
public:
virtual void initialize(double side_length) = 0;
virtual double area() = 0;
virtual ~RegularPolygon(){}
protected:
RegularPolygon(){}
};
};
#endif
在建立plugin的時候就需要去include該class,並且新增兩個class做實作,分別是triangle和square:
in polygon_plugins.h:
#ifndef PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_
#define PLUGINLIB_TUTORIALS__POLYGON_PLUGINS_H_
#include <pluginlib_tutorials_/polygon_base.h>
#include <cmath>
namespace polygon_plugins
{
class Triangle : public polygon_base::RegularPolygon
{
public:
Triangle(){}
void initialize(double side_length)
{
side_length_ = side_length;
}
double area()
{
return 0.5 * side_length_ * getHeight();
}
double getHeight()
{
return sqrt((side_length_ * side_length_) - ((side_length_ / 2) * (side_length_ / 2)));
}
private:
double side_length_;
};
class Square : public polygon_base::RegularPolygon
{
public:
Square(){}
void initialize(double side_length)
{
side_length_ = side_length;
}
double area()
{
return side_length_ * side_length_;
}
private:
double side_length_;
};
};
#endif
接著在cpp實作的部分加入plugin的設定:
in polygon_plugins.cpp:
#include <pluginlib/class_list_macros.h>
#include <pluginlib_tutorials_/polygon_base.h>
#include <pluginlib_tutorials_/polygon_plugins.h>
PLUGINLIB_EXPORT_CLASS(polygon_plugins::Triangle, polygon_base::RegularPolygon)
PLUGINLIB_EXPORT_CLASS(polygon_plugins::Square, polygon_base::RegularPolygon)
並且在CMakeList.txt和package.xml進行編譯的規則:
in CMakeList.txt:
include_directories(include)
add_library(polygon_plugins src/polygon_plugins.cpp)
in package.xml:
<library path="lib/libpolygon_plugins">
<class type="polygon_plugins::Triangle" base_class_type="polygon_base::RegularPolygon">
<description>This is a triangle plugin.</description>
</class>
<class type="polygon_plugins::Square" base_class_type="polygon_base::RegularPolygon">
<description>This is a square plugin.</description>
</class>
</library>
建立好一個plugin以後,要使用就很簡單啦,就新增include以後就可以使用了:
in polygon_loader.cpp :
#include <pluginlib/class_loader.h>
#include <pluginlib_tutorials_/polygon_base.h>
int main(int argc, char** argv)
{
pluginlib::ClassLoader<polygon_base::RegularPolygon> poly_loader("pluginlib_tutorials_", "polygon_base::RegularPolygon");
try
{
boost::shared_ptr<polygon_base::RegularPolygon> triangle = poly_loader.createInstance("polygon_plugins::Triangle");
triangle->initialize(10.0);
boost::shared_ptr<polygon_base::RegularPolygon> square = poly_loader.createInstance("polygon_plugins::Square");
square->initialize(10.0);
ROS_INFO("Triangle area: %.2f", triangle->area());
ROS_INFO("Square area: %.2f", square->area());
}
catch(pluginlib::PluginlibException& ex)
{
ROS_ERROR("The plugin failed to load for some reason. Error: %s", ex.what());
}
return 0;
}
plugin筆者在看的時候一直覺得跟package很像,後來想想,package就是不同的套件,內有完整的專案功能,而plugin就比較像是新增的一些小功能,需要依附在特定的package底下才能進行實作,因為跟原本的package內的一些class有相同的特性,卻需要抽換不同的實作方法,因此可以用到plugin這個功能。以上述範例為例,三角形和長方形都具有多邊形的特性,但是卻有不同的實作例如計算周長等,基本上就是利用plugin做到多型的處理。
http://wiki.ros.org/pluginlib
http://wiki.ros.org/pluginlib/Tutorials/Writing%20and%20Using%20a%20Simple%20Plugin